package tech.pdai.springboot.redis.jedis.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Service;

// 参考文档：https://mp.weixin.qq.com/s/t1eldoYmrAGQskdJKN4gZQ
@Slf4j
@Service
public class RedisConsumerService<T> implements CommandLineRunner {

    private final RedisMessageQueue redisMessageQueue;

    private final static String QUEUE_NAME = "TMP";

    private static int MAX_RETRY_COUNT = 3;

    public RedisConsumerService(RedisMessageQueue redisMessageQueue) {
        this.redisMessageQueue = redisMessageQueue;
    }

    @Override
    public void run(String... args) throws Exception {
        new Thread(() -> {
            consumerMessage(Object.class); // todo... 待修改
        }, "message-consumer").start();

    }

    private <T> void consumerMessage(Class<T> clazz) {
        while(!Thread.currentThread().isInterrupted()) {
            try {
                T message = redisMessageQueue.blockingReceiveMessage(QUEUE_NAME, clazz);
                if(message!=null) {
                    //
                    processMessage(message);
                }
            }catch (Exception e) {
                log.error("消费消息异常", e);
                try {
                    // 发生异常时，短暂休眠避免CPU空转
                    Thread.sleep(1000);
                }catch (InterruptedException e1) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }

        log.info("消费消息已停止");
    }

    /**
     * 处理消息
     * @param message
     * @param <T>
     */
    private <T> void processMessage(T message) {
        log.info("处理消息: {}", message);
        int retryCount = 0;
        boolean flag = false;
        while (retryCount < MAX_RETRY_COUNT &&  !flag) {
            try{
                // 处理消息的逻辑
                // TODO...
                flag = true;
            }catch (Exception e) {
                retryCount++;
                log.error("处理消息异常, 重试次数: {}", retryCount, e);

                if (retryCount >= MAX_RETRY_COUNT) {
                    log.error("处理消息异常, 重试次数已达最大次数, 消息: {}", message);
                    //放入死信队列
                    redisMessageQueue.sendToDeadLetterQueue(QUEUE_NAME, message,
                            "达到最大重试次数:" + retryCount + ",异常信息:" + e.getMessage());
                }else {
                    try {
                        // 发生异常时，短暂休眠避免CPU空转
                        Thread.sleep(1000L * (1L << retryCount)); // 1s 2s 4s
                    }catch (InterruptedException e1) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }

            }
        }
    }
}
